﻿namespace MicroCloud.Entity
{
    /// <summary>
    /// 数据实体映射配置基类
    /// </summary>
    /// <typeparam name="TEntity">实体类型</typeparam>
    /// <typeparam name="TKey">实体主键类型</typeparam>
    public abstract class EntityTypeConfigurationBase<TEntity, TKey> : IEntityTypeConfiguration<TEntity>, IEntityRegister
        where TEntity : class, IEntity<TKey>
        where TKey : IEquatable<TKey>
    {
        #region 属性
        /// <summary>
        /// 获取 是否启用
        /// <para>默认 true，设定为 false 后需另外自行实现，如继承现有实体后重写操作。</para>
        /// </summary>
        public virtual bool Enabled => true;

        /// <summary>
        /// 获取 所属的数据上下文类型
        /// </summary>
        public virtual Type DbContextType => typeof(DefaultDbContext);

        /// <summary>
        /// 获取 实体类型
        /// </summary>
        public Type EntityType => typeof(TEntity);

        /// <summary>
        /// 获取 实体名称
        /// </summary>
        public string EntityName => EntityType.Name;

        /// <summary>
        /// 获取 实体类型所属的数据上下文类型
        /// </summary>
        public Type DbContextTypeForEntity => ServiceLocator.Instance?.GetService<IEntityManager>()?.GetDbContextTypeForEntity(EntityType);

        /// <summary>
        /// 获取 数据上下文配置信息
        /// </summary>
        public DbContextOption DbContextOptions => ServiceLocator.Instance?.GetMicroCloudOptions()?.GetDbContextOptions(DbContextTypeForEntity);

        #endregion

        #region 方法
        /// <summary>
        /// 将当前实体类映射对象注册到数据上下文模型构建器中
        /// </summary>
        /// <param name="modelBuilder">上下文模型构建器</param>
        public void RegisterTo(ModelBuilder modelBuilder)
        {
            modelBuilder.ApplyConfiguration(this);
            // 给软删除的实体添加全局过滤器
            if (typeof(ISoftDeletable).IsAssignableFrom(EntityType))
            {
                modelBuilder.Entity<TEntity>().HasQueryFilter(m => ((ISoftDeletable)m).DeletedTime == null);
            }
        }

        /// <summary>
        /// 实体类型的数据库配置
        /// </summary>
        /// <param name="builder">实体类型构建器</param>
        public virtual void Configure(EntityTypeBuilder<TEntity> builder)
        {
            var allowTypes = new[] {
                                typeof(string[]),
                                typeof(bool[]),
                                typeof(short[]),
                                typeof(ushort[]),
                                typeof(int[]),
                                typeof(uint[]),
                                typeof(long[]),
                                typeof(ulong[]),
                                typeof(Int128[]),
                                typeof(UInt128[]),
                                typeof(double[]),
                                typeof(decimal[]),
                                typeof(DateTime[]),
                                typeof(Guid[]),
                                typeof(Enum[]) };
            //&& !o.IsVirtual()
            var arrayProperties = EntityType.GetProperties().Where(o => o.MemberType == MemberTypes.Property && o.CanRead && o.CanWrite
                && o.GetAttribute<NotMappedAttribute>() == null && !o.HasAttribute<NotConvertAttribute>() && o.PropertyType.IsArray
                && allowTypes.Contains(o.PropertyType)).ToList();
            if (arrayProperties?.Count > 0)
            {
                foreach (var arrayProperty in arrayProperties)
                {
                    var propertyName = arrayProperty.Name;
                    #region EF JSON列配置模式 --- 目前不支持基元类型的集合映射，故注释备查。
                    //builder.OwnsMany(arrayProperty.PropertyType, propertyName
                    //    , ownedNavigationBuilder =>
                    //    {
                    //        ownedNavigationBuilder.ToJson();
                    //    });
                    #endregion
                    if (arrayProperty.PropertyType == typeof(string[]))
                    {
                        builder.Property(propertyName).HasJsonConversion<string[]>();
                    }
                    else if (arrayProperty.PropertyType == typeof(bool[]))
                    {
                        builder.Property(propertyName).HasJsonConversion<bool[]>();
                    }
                    else if (arrayProperty.PropertyType == typeof(short[]))
                    {
                        builder.Property(propertyName).HasJsonConversion<short[]>();
                    }
                    else if (arrayProperty.PropertyType == typeof(ushort[]))
                    {
                        builder.Property(propertyName).HasJsonConversion<ushort[]>();
                    }
                    else if (arrayProperty.PropertyType == typeof(int[]))
                    {
                        builder.Property(propertyName).HasJsonConversion<int[]>();
                    }
                    else if (arrayProperty.PropertyType == typeof(uint[]))
                    {
                        builder.Property(propertyName).HasJsonConversion<uint[]>();
                    }
                    else if (arrayProperty.PropertyType == typeof(long[]))
                    {
                        builder.Property(propertyName).HasJsonConversion<long[]>();
                    }
                    else if (arrayProperty.PropertyType == typeof(ulong[]))
                    {
                        builder.Property(propertyName).HasJsonConversion<ulong[]>();
                    }
                    else if (arrayProperty.PropertyType == typeof(Int128[]))
                    {
                        builder.Property(propertyName).HasJsonConversion<Int128[]>();
                    }
                    else if (arrayProperty.PropertyType == typeof(UInt128[]))
                    {
                        builder.Property(propertyName).HasJsonConversion<UInt128[]>();
                    }
                    else if (arrayProperty.PropertyType == typeof(double[]))
                    {
                        builder.Property(propertyName).HasJsonConversion<double[]>();
                    }
                    else if (arrayProperty.PropertyType == typeof(decimal[]))
                    {
                        builder.Property(propertyName).HasJsonConversion<decimal[]>();
                    }
                    else if (arrayProperty.PropertyType == typeof(DateTime[]))
                    {
                        builder.Property(propertyName).HasJsonConversion<DateTime[]>();
                    }
                    else if (arrayProperty.PropertyType == typeof(Guid[]))
                    {
                        builder.Property(propertyName).HasJsonConversion<Guid[]>();
                    }
                    else if (arrayProperty.PropertyType == typeof(Enum[]))
                    {
                        builder.Property(propertyName).HasJsonConversion<Enum[]>();
                    }

                }
            }

            Configuration(builder);
        }

        /// <summary>
        /// 额外的数据映射
        /// </summary>
        /// <param name="builder">实体类型构建器</param>
        public virtual void Configuration(EntityTypeBuilder<TEntity> builder)
        {
            ConfigurationAppend(builder);
        }


        /// <summary>
        /// 额外的数据映射
        /// </summary>
        /// <param name="builder">实体类型构建器</param>
        protected virtual void ConfigurationAppend(EntityTypeBuilder<TEntity> builder) { }

        #endregion
    }

}
